package com.wwg.security;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

/**
 * 接口请求加密，验签工具类
 */
public class CyRequestVerifyUtil {

//	private static String MD5_KEY = "1234567890abcdef";
	private static String MD5_KEY = "06671ccfad19459c9ebce61c3678fd87";

	private static Logger logger = LoggerFactory.getLogger(CyRequestVerifyUtil.class);

	/**
	 * @param requestData
	 * @return EsReturnDto
	 */
	public static EsReturnDto verifyMd5(String requestData)
	{
		logger.debug("md5 verify ....  requestData = {}",requestData);
		EsReturnDto returnDto = new EsReturnDto();
		//校验请求参数是否为空
		if(StringUtils.isEmpty(requestData))
		{
			returnDto.setResultCode("-1");
			returnDto.setInfo("入参为空");
			logger.error("入参为空");
			return returnDto;
		}
		//校验请求参数长度
		if(requestData.length()<32)
		{
			returnDto.setResultCode("-2");
			returnDto.setInfo("入参长度非法");
			logger.error("入参长度非法");
			return returnDto;
		}

		//验证 MD5
		String md5 = requestData.substring(0,32);
		logger.debug("md5 = {}",md5);
		String data = requestData.substring(32,requestData.length());
		logger.debug("data = {}",data);

		String md5key = MD5.hmacSign(MD5_KEY+data);
		logger.debug("md5key = {}",md5key);
		if(!md5.equals(md5key))
		{
			returnDto.setResultCode("-3");
			returnDto.setInfo("校验结果非法");
			logger.error("校验结果非法");
			return returnDto;
		}

		returnDto.setInfo(data);
		returnDto.setResultCode("0");
		logger.debug("md5 verify success.");
		return returnDto;
	}

	/**
	 * json 字符串 MD5 签名
	 * @param jsonData
	 * @return
	 */
	public static String getMD5SignedString(String jsonData)
	{
		logger.debug("jsonData = {}",jsonData);
		String md5 = MD5.hmacSign(MD5_KEY+jsonData);
		logger.debug("md5 = {}",md5);
		String rtnString= md5+jsonData;
		logger.debug("rtnString = {}",rtnString);
		return rtnString;
	}

	public static void main(String[] args) {
		String json="{\n" +
				"    \"logisticid\": \"BK20211119001223\",\n" +
				"    \"order_source\": \"4\",\n" +
				"    \"order_goodstype\": \"2\",\n" +
				"    \"order_type\": \"JTM\",\n" +
				"    \"order_pcs\": 1,\n" +
				"    \"weight\": 1,\n" +
				"    \"weight_unit\": \"KG\",\n" +
				"    \"order_height\": null,\n" +
				"    \"order_length\": null,\n" +
				"    \"order_width\": null,\n" +
				"    \"service_code\": \"JTM\",\n" +
				"    \"volume_weight\": null,\n" +
				"    \"order_paytype\": 1,\n" +
				"    \"business_type\": \"2\",\n" +
				"    \"cust_code\": \"\",\n" +
				"    \"sender\": {\n" +
				"        \"status\": \"1\",\n" +
				"        \"name\": \"TEST KEYWORD\",\n" +
				"        \"country\": \"CN\",\n" +
				"        \"prov\": \"上海\",\n" +
				"        \"city\": \"上海市\",\n" +
				"        \"area\": \"青浦区\",\n" +
				"        \"areacode\": \"8888\",\n" +
				"        \"postcode\": \"000000\",\n" +
				"        \"address\": \"Samad Rumah ttttttttttttttttttt\",\n" +
				"        \"mobile\": \"6012345\",\n" +
				"        \"phone\": \"6012345\",\n" +
				"        \"type\": \"1\",\n" +
				"        \"ccltype\": \"TRN\",\n" +
				"        \"cclnumber\": \"566664623233264\",\n" +
				"        \"name_cn\": \"TEST KEYWORD\",\n" +
				"        \"company\": \"ss\"\n" +
				"    },\n" +
				"    \"receiver\": {\n" +
				"        \"address\": \"1adfdsafasd\",\n" +
				"        \"area\": \"QINZHOU DISTRICT\",\n" +
				"        \"areacode\": \"86\",\n" +
				"        \"ccltype\": \"1111\",\n" +
				"        \"city\": \"TIANSHUI CITY\",\n" +
				"        \"country\": \"CN\",\n" +
				"        \"mobile\": \"+86-18638794135\",\n" +
				"        \"name\": \"wen\",\n" +
				"        \"name_cn\": \"11\",\n" +
				"        \"phone\": \"123152\",\n" +
				"        \"postcode\": \"620500\",\n" +
				"        \"prov\": \"GANSU\",\n" +
				"        \"type\": \"1\",\n" +
				"        \"cclnumber\":\"11111\"\n" +
				"    },\n" +
				"    \"declared\": {\n" +
				"        \"amount\": 0,\n" +
				"        \"currency\": \"RM\"\n" +
				"    },\n" +
				"    \"items\": [\n" +
				"        {\n" +
				"            \"item_name\": \"FULL OPERATION TEST\",\n" +
				"            \"currency\": \"RM\",\n" +
				"            \"item_value\": 25,\n" +
				"            \"desc\": \"FULL OPERATION TEST\",\n" +
				"            \"item_unit\": \"pcs\",\n" +
				"            \"item_univalent\": 25,\n" +
				"            \"aos\": \"ttttttttttttttttttttt\",\n" +
				"            \"pcs\": 1\n" +
				"        }\n" +
				"    ]\n" +
				"}";

		String md5SignedString = getMD5SignedString(json);

//		System.out.println(md5SignedString);

//		System.out.println("-----------------------------校验");
		verifyMd5(md5SignedString);

//		System.out.println("-----------------------------");
//		System.out.println(esReturnDto);

	}

	/**
	 *
	 * @date 2015年9月30日 上午11:15:16
	 * @version V1.0
	 */
	static class MD5 {
		static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(MD5.class);
		public static final String ENCODE = "GBK"; // UTF-8
		private static final String KEY = "zjgdzwhy@qq.com-888&()adf";

		private MD5() {
		}

		public static String hmacSign(String aValue) {
			byte k_ipad[] = new byte[64];
			byte k_opad[] = new byte[64];
			byte keyb[];
			byte value[];
			try {
				keyb = KEY.getBytes(ENCODE);
				value = aValue.getBytes(ENCODE);
			} catch (UnsupportedEncodingException e) {
				logger.error(
						"MD5 UnsupportedEncodingException=>>" + e.getMessage(), e);
				keyb = KEY.getBytes();
				value = aValue.getBytes();
			}
			Arrays.fill(k_ipad, keyb.length, 64, (byte) 54);
			Arrays.fill(k_opad, keyb.length, 64, (byte) 92);
			for (int i = 0; i < keyb.length; i++) {
				k_ipad[i] = (byte) (keyb[i] ^ 0x36);
				k_opad[i] = (byte) (keyb[i] ^ 0x5c);
			}

			MessageDigest md = null;
			try {
				md = MessageDigest.getInstance("MD5");
			} catch (NoSuchAlgorithmException e) {
				logger.error("MD5 NoSuchAlgorithmException=>>" + e.getMessage(), e);
				return null;
			}
			md.update(k_ipad);
			md.update(value);
			byte dg[] = md.digest();
			md.reset();
			md.update(k_opad);
			md.update(dg, 0, 16);
			dg = md.digest();
			return MD5.toHex(dg);
		}

		public static String digest(String aValue) {

			byte value[];
			try {
				value = aValue.trim().getBytes(ENCODE);
			} catch (UnsupportedEncodingException e) {
				logger.error(
						"MD5 UnsupportedEncodingException=>>" + e.getMessage(), e);
				value = aValue.trim().getBytes();
			}
			MessageDigest md = null;
			try {
				md = MessageDigest.getInstance("SHA");
			} catch (NoSuchAlgorithmException e) {
				logger.error("MD5 NoSuchAlgorithmException=>>" + e.getMessage(), e);
				return null;
			}
			return MD5.toHex(md.digest(value));
		}

		public static String toHex(byte input[]) {
			if (input == null)
				return null;
			StringBuilder output = new StringBuilder(input.length * 2);
			for (int i = 0; i < input.length; i++) {
				int current = input[i] & 0xff;
				if (current < 16)
					output.append("0");
				output.append(Integer.toString(current, 16));
			}

			return output.toString();
		}

	}

	static class EsReturnDto implements Serializable {

		private static final long serialVersionUID = 792812341139190348L;

		//返回消息
		private String info;

		//返回消息码
		private String resultCode;

		private Object data;

		public EsReturnDto(){

		}

		public EsReturnDto(String resultCode,String info){
			this.resultCode = resultCode;
			this.info = info;
		}

		public EsReturnDto(String resultCode,String info, Object data){
			this.resultCode = resultCode;
			this.info = info;
			this.data = data;
		}

		public boolean isSuccess()
		{
			if("0000".equals(this.resultCode))
			{
				return true;
			}else
			{
				return false;
			}
		}

		public Object getData() {
			return data;
		}

		public void setData(Object data) {
			this.data = data;
		}

		public String getInfo() {
			return info;
		}

		public void setInfo(String info) {
			this.info = info;
		}

		public String getResultCode() {
			return resultCode;
		}

		public void setResultCode(String resultCode) {
			this.resultCode = resultCode;
		}

		@Override
		public String toString() {
			return "EsReturnDto [info=" + info + ", resultCode=" + resultCode + ", data=" + data + "]";
		}
	}


}
